/*

Copyright (C) 2007 Thomas Geiger (tom.geiger@gmail.com)

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

*/

#include "octavexml/octave_xml.h"
#include "octavexml/OctaveXMLReader.h"
#include "octavexml/OctaveXMLWriter.h"

#include "gt-ls.h"

/*
 *  enum load_save_format
00034   {
00035     LS_ASCII,
00036     LS_BINARY,
00037     LS_MAT_ASCII,
00038     LS_MAT_ASCII_LONG,
00039     LS_MAT_BINARY,
00040     LS_MAT5_BINARY,
00041     LS_MAT7_BINARY,
00042 #ifdef HAVE_HDF5
00043     LS_HDF5,
00044 #endif // HAVE_HDF5
00045     LS_UNKNOWN
00046   };
*/

bool set_format(load_save_format& format, std::string& flag) {
	if (flag == "ascii" || flag == "text" ) {
		format = LS_ASCII;	
	} else if (flag == "binary") {
		format = LS_BINARY;	
	} else if (flag == "mat" || flag == "mat-binary") {
		format = LS_MAT_BINARY;
	//} else if (flag == "hdf5") {
	//	format = LS_HDF5;		
	} else if (flag == "xml") {
		format = LS_UNKNOWN;	
	} else {
		return false;
	}
	return true;
}

octave_value_list load_data(istream& input, load_save_format& format, const octave_value_list& vars) {
	
	octave_value_list retval;
	bool global = false;
	bool force = true;
	int nargout = 1;
	int offset = 3;

	if (format != LS_UNKNOWN) {
		bool swap = false;	
		oct_mach_info::float_format float_fmt;
		bool list_only = false;
		bool verbose = true;
		
		// ok
		int argc = vars.length() + 1;
		string_vector argv = vars.make_argv("load");

		// first argument is url, the following ones are the variables 
		// to extract, if none, then the whole file will be read
		retval = do_load (input, "", force,
			 format, float_fmt, list_only, swap, verbose,
		 	argv, offset, argc, nargout);
	} else {
		
		//TODO: this is quick solution 
		// only applicable for small files
		// usage of low level c++ stream methods
		// might improve performance here
		
		
		input.seekg (0, ios::end);
		int length = input.tellg();
		if (length <= 0) {			
			retval = octave_value(false);
			return retval;
		}
		length = length -1;
		input.seekg (0, ios::beg);

		// allocate memory
		char* buffer = new char [length];
		input.read (buffer,length);

		istringstream ss;
		ss.str(string(buffer));

		OctaveXMLReader reader;
		// turn off validation
		reader.setValidation(false);
		reader.setFormat(FMT_TYPESAFE);
		if ( !reader.readXML(ss, retval) ) {
			retval = octave_value(false);
		}
	}
	return retval;
}


// copied from octave load_save.cc, modified to support xml
static int save_vars (ostream& os, const string& pattern, load_save_format& format, bool save_as_floats)
{
	Array<symbol_record *> vars = curr_sym_tab->glob
    				(pattern, symbol_record::USER_VARIABLE, SYMTAB_ALL_SCOPES);

  	int saved = vars.length();
  	bool infnan_warned = false;

	if (format == LS_UNKNOWN) { // in this case we expect it to be xml
		
		ostringstream oss;
		
		OctaveXMLWriter writer;
		writer.setFormat(FMT_TYPESAFE);
		for (int i = 0; i < saved; i++)
  		{  					
  			// process to xml, make sure a var is passed to the function 
			if ( !writer.writeXML(vars(i)->def(), oss) ) {
				return 0;
			}
  		}	
		
		os << oss.str();
		
	} else {
		for (int i = 0; i < saved; i++)
  		{
  			do_save(os, vars(i), format, save_as_floats, infnan_warned);

    		if (error_state)
				break;
  		}
	}
  	return saved;
}

void save_data(ostream& output, load_save_format& format, const octave_value_list& vars) {
	
	int argc = vars.length() + 1;  // counting starts with 1
	string_vector argv = vars.make_argv("save");
		
	int argv_idx = 3;  // ignore function name and file destination
		
	bool save_as_floats = false;
	bool write_header_info = true;
	
	if (write_header_info)
	   	write_header (output, format);
	
	if (argv_idx == argc)
	{
	  	save_vars (output, "*", format, save_as_floats);
	}
	else
	{
		for (int i = argv_idx; i < argc; i++)
		{
			if (!save_vars (output, argv[i], format, save_as_floats))
		   	{
		   		warning ("save: no such variable `%s'", argv[i].c_str ());
		   	}
		}
	}
	
}


